package com.deep.test.thread.concurrent;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.TimeUnit;

/**
 * <p>Description:WaitThread和NotifyThread，前者检查
 flag值是否为false，如果符合要求，进行后续操作，否则在lock上等待，后者在睡眠了一段时间
 后对lock进行通知</p>
 * 1）使用wait()、notify()和notifyAll()时需要先对调用对象加锁。
 2）调用wait()方法后，线程状态由RUNNING变为WAITING，并将当前线程放置到对象的
 等待队列。
 3）notify()或notifyAll()方法调用后，等待线程依旧不会从wait()返回，需要调用notify()或
 notifAll()的线程释放锁之后，等待线程才有机会从wait()返回。4）notify()方法将等待队列中的一个等待线程从等待队列中移到同步队列中，而notifyAll()
 方法则是将等待队列中所有的线程全部移到同步队列，被移动的线程状态由WAITING变为
 BLOCKED。
 5）从wait()方法返回的前提是获得了调用对象的锁
 * author:hudepin
 * createTime:2018/7/5 16:57
 */
public class WaitNotify {
    static Object lock = new Object();
    static boolean flag = true;
    public static void main(String[] args) throws InterruptedException {
        Thread waitThread = new Thread(new Wait(), "WaitThread");
        waitThread.start();
        TimeUnit.SECONDS.sleep(1);
        Thread notifyThread = new Thread(new Notify(), "NotifyThread");
        notifyThread.start();
    }
    static class Wait implements Runnable{

        @Override
        public void run() {
            //加锁，拥有lock的Monitor
            synchronized (lock){
                // 当条件不满足时，继续wait，同时释放了lock的锁
                while(flag){
                    try {
                        System.out.println("Thread:"+Thread.currentThread().getName()+"flag is true and wait lock"
                                +new SimpleDateFormat("HH:mm:ss").format(new Date()));
                        lock.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }

                }
                //条件满足时，完成工作
                System.out.println("Thread:"+Thread.currentThread().getName()+"flag is false lock notify 后执行"
                        +new SimpleDateFormat("HH:mm:ss").format(new Date()));

            }
        }
    }
    static class Notify implements Runnable{

        @Override
        public void run() {
            //加锁，拥有lock的Monitor
            synchronized (lock){
            // 获取lock的锁，然后进行通知，通知时不会释放lock的锁，
            // 直到当前线程释放了lock后，WaitThread才能从wait方法中返回
                    try {
                        System.out.println("Thread:"+Thread.currentThread().getName()+"hold lock "
                                +new SimpleDateFormat("HH:mm:ss").format(new Date()));
                        lock.notify();
                        flag =false;
                        SleepUtils.sleep(5);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
            }
            //再次加锁
            synchronized (lock){
                System.out.println("Thread:"+Thread.currentThread().getName()+"hold lock again "
                        +new SimpleDateFormat("HH:mm:ss").format(new Date()));
            }
        }
    }

}
